// Desktop.cpp : Implementation of CDesktop
#include "stdafx.h"
#include "Desktop.h"
#include "dispTestObject.h"
#include "dispTestObjectList.h"
#include "jniEnvironment.h"
#include "java.h"
#include "jniString.h"
#include "jniReference.h"
#include "jtf.h"
#include "customException.h"

STDMETHODIMP CDesktop::InterfaceSupportsErrorInfo(REFIID riid)
{
  static const IID* arr[] = 
  {
    &IID_IDesktop
  };

  for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
  {
    if (InlineIsEqualGUID(*arr[i],riid))
      return S_OK;
  }
  return S_FALSE;
}

STDMETHODIMP CDesktop::Connect(BSTR hostname, LONG port)
{
  try 
  {
    delete mpJtfDesktop;
    mpJtfDesktop = new CJtfDesktop(this, hostname, port);
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

STDMETHODIMP CDesktop::Attach(BSTR moduleNamePattern, BSTR commandLinePattern, BSTR techDomains)
{
  try
  {
    GetJtfDesktop()->Attach(moduleNamePattern, commandLinePattern, techDomains);
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

STDMETHODIMP CDesktop::DetachAll(void)
{
  try 
  {
    GetJtfDesktop()->DetachAll();
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

STDMETHODIMP CDesktop::ExecuteBaseState(BSTR executable, BSTR commandLine, BSTR mainWindowLocator, BSTR techDomains, IDispatch **mainWindow)
{
  try 
  {
    *mainWindow = GetJtfDesktop()->ExecuteBasestate(executable, commandLine, mainWindowLocator, techDomains);
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

STDMETHODIMP CDesktop::ExecuteBrowserBaseState(BSTR executable, BSTR url, BSTR mainWindowLocator, BSTR techDomains, IDispatch **mainWindow)
{
  try {
    *mainWindow = GetJtfDesktop()->ExecuteBrowserBasestate(executable, url, mainWindowLocator, techDomains);
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

STDMETHODIMP CDesktop::Find(BSTR locator, IDispatch** testObject)
{
  try 
  {
    *testObject = GetJtfDesktop()->Find(locator);
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

STDMETHODIMP CDesktop::FindAll(BSTR locator, IDispatch** testObjects)
{
  try 
  {
    *testObjects = GetJtfDesktop()->FindAll(locator);
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

STDMETHODIMP CDesktop::GetParent(IDispatch** testObject)
{
  *testObject = NULL; // Desktop has no parent
  return S_OK;
}

STDMETHODIMP CDesktop::GetChildren(IDispatch** testObjects)
{
  try 
  {
    *testObjects = GetJtfDesktop()->GetChildren();
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

STDMETHODIMP CDesktop::GetOption(BSTR optionName, VARIANT* optionValue)
{
  try 
  {
    if (optionValue)
      GetJtfDesktop()->GetOption(optionName, optionValue);
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

STDMETHODIMP CDesktop::GetTechDomainOption(BSTR optionName, BSTR techDomainName, VARIANT* optionValue)
{
  try 
  {
    if (optionValue)
      GetJtfDesktop()->GetTechDomainOption(optionName, techDomainName, optionValue);
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

STDMETHODIMP CDesktop::ResetAllOptions(void)
{
  try 
  {
    GetJtfDesktop()->ResetAllOptions();
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

STDMETHODIMP CDesktop::SetOption(BSTR optionName, VARIANT optionValue)
{
  try 
  {
    GetJtfDesktop()->SetOption(optionName, optionValue);
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

STDMETHODIMP CDesktop::SetTechDomainOption(BSTR optionName, BSTR techDomainName, VARIANT optionValue)
{
  try 
  {
    GetJtfDesktop()->SetTechDomainOption(optionName, techDomainName, optionValue);
    return S_OK;
  }
  catch (CustomException& e)
  {
    return e.SetErrorInfoAndReturn(E_FAIL, IID_IDesktop);
  }
}

CJtfDesktop* CDesktop::GetJtfDesktop()
{
  if (!mpJtfDesktop) 
    mpJtfDesktop = new CJtfDesktop(this);
  return mpJtfDesktop;
}

int CDesktop::GetHashCode(jobject jobjTestObject)
{
  JtfAbstractTestObjectClass jtfTestObject;
  JavaObjectClass javaObject;
  CJniLocalReference<jobject> jobjHandle = jtfTestObject.GetHandle.Invoke(jobjTestObject);
  int hashCode = 0;
  if (jobjHandle)
  {
    hashCode = javaObject.HashCode.Invoke(jobjHandle.Get());
  }
  else
  {
    hashCode = javaObject.HashCode.Invoke(jobjTestObject);
  }
  return hashCode;
}

IDispatch* CDesktop::CreateDispTestObject(jobject jobjTestObject)
{
  JtfDesktopClass jtfDesktop;
  if (jtfDesktop.IsInstance(jobjTestObject))
  {
    IDispatch* pThis = 0;
    QueryInterface(IID_IDispatch, (void**)&pThis);
    return pThis;
  }
  else
  {
    // look up existing object first
    int hashCode = GetHashCode(jobjTestObject);
    std::map<int, IDispatch*>::iterator itFound = mDispTestObjects.find(hashCode);
    if (itFound != mDispTestObjects.end())
    {
      IDispatch* pExisting = 0;
      itFound->second->QueryInterface(IID_IDispatch, (void**)&pExisting);
      return pExisting;
    }
    // create new object
    IDispatch* pNewTestObject = new CDispTestObject(this, jobjTestObject);
    mDispTestObjects[hashCode] = pNewTestObject;
    return pNewTestObject;
  }
}

void CDesktop::UnregisterTestObject(jobject jobjTestObject)
{
  int hashCode = GetHashCode(jobjTestObject);
  mDispTestObjects.erase(hashCode);
}

IDispatch* CDesktop::CreateDispTestObjectList(jobject jobjListOfTestObjects)
{
  return new CDispTestObjectList(this, jobjListOfTestObjects);
}
